/*
* webpack.config.js webpack的配置文件
*  作用：指示webpack做什么操作，（运行命令时，会加载里面配置）
*   所有的构建工具是基于node.js平台运行的 模块化默认采用common.js
* */

/*
* 缓存:
    babel缓存
        cacheDirectory: true
    文件资源缓存
        hash:每次webpack构建时会生成- -个唯一的hash值。
        问题:因为js 和css同时使用- - 个hash值。
            如果重新打包，会导致所有缓存失效。(可能我却只改动-一个文件)
        chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk，那么hash值就一样
         问题：js和css的hash值还是一样的
              因为css是在js中被引入的，所属于一个chunk
        contenthash：根据文件的内容生成hash值，不同文件的hash值一定不一样
*/
/*
* tree shaking 去除无用的代码
*    前提：1、必须使用ES6模块化  2、开启production环境
*    作用：减少代码体积
*   "sideEffects":false,所有代码都没有副作用（都可以进行tree shaking）
*   问题：可能会把css/@babel/polyfill文件干掉
*    package.json中配置
*       解决这样配置 "sideEffects":["*.css","*.less]
**/
//resolve用来拼接绝对路径的方法
const path = require('path');
//处理html的插件
const HtmlWebpackPlugin=require('html-webpack-plugin');
//提取js中的css成单独文件插件
const MiniCssExtractPlugin=require('mini-css-extract-plugin');
//压缩css插件
const OptimizeCssAssetsWebpackPlugin=require('optimize-css-assets-webpack-plugin');
//  PWA：渐进式网络开发应用程序(离线可访问) 可以安装插件 workbox --> workbox-webpack-plugin 记录还未安装使用
//const workboxWebpackPlugin=require('workbox-webpack-plugin');
//设置node环境变量,决定browserslist是那个环境
process.env.NODE_ENV='development'
module.exports = {
    /*
    * entry：入口七点
    * 1、string-->'./src/index.js' 打包形成一个chunk。输出一个bundle文件
    * 2、array-->['./src/index.js','./src/demo.js']  多入口，所有文件最终只会形成一个chunk，输出一个输出一个bundle文件。
    *         -->只有在HMR功能中html热生效  ['./src/index.js','./src/index.html']
    * 3、object-->{index:'./src/index.js',demo:'./src/demo.js' }
    *          多入口
    *          有几个入口文件就形成几个chunk，输出几个bundle文件
    *          此时的chunk的名称是key
    * */
    //入口，以那个文件入口起点开始打包，分析构建依赖图
    entry: ['./src/index.js','./src/index.html'],
    //打包后资源bundles输出到哪里，以名字命名
    //__dirname 是node.js的变量，代表当前文件目录的绝对路径
    output: {
        filename: '[name].[contenthash:10].js',//输出文件名（绝对路径）[name]入口什么名就是什 么名 文件名称（目录/指定名称）
        path: path.resolve(__dirname, 'build'),//输出文件目录（将所有的资源输出到公共目录）
    },
    //loader的配置,Loader让webpack能够去处理非js文件（webpack自身只理解javascript）
    module: {
        rules: [
            //详细的loader配置
            {
                /*语法检查
           * eslint eslint-loader
           * 只检查自己写的源代码
           * 设置检查规则：
           *   package.json中的eslintConfig中设置
           *   "eslintConfig":{
           *       "extends":"airbnb-base"
           * }
           *   airbnb -->eslint-config-airbnb-base eslint-plugin-import
           * */
                // {
                //     test:/\.js$/,
                //     exclude:/node_modules/,
                //     //只检查src下的js文件
                //     include:resolve(__dirname,'src'),
                //      //优先执行
                //     enforce:'pre',
                //     loader: "eslint-loader",
                //     options: {
                //        //自动修复eslint的错误
                //        fix:true
                //     }
                // },
            },
            {
                //优化生产环境打包构建速度，以下的loader只会匹配一个
                //注意：不能有两个配置处理同一个类型文件
                oneOf: [
                    {
                        //代表匹配哪些文件
                        test:/\.css$/,
                        //使用哪些loader进行处理,不同的文件用不同的loader进行处理
                        use:[
                            //user中的执行顺序，从右到左，从上到下 一次执行
                            //创建的style标签，将js中的样式资源插入进行，添加到head中生效,当将css打包单独文件时不使用
                            //'style-loader',
                            //这个loader取代style-loader。作用：提取js中的css成单独文件。
                            MiniCssExtractPlugin.loader,
                            //将css文件处理成common.js模块加载到js中，里面的内容是样式字符串
                            'css-loader',
                            /*
                            * css兼容性处理：postcss-->postcss-loader postcss-preset-env插件
                            *postcss-preset-env插件帮postcss找到package.json中browserslist里面的配置，通过配置加载指定的css兼容性样式
                            *
                            * "browserslist": {
                            *   //开发环境
                            *   需要设置process.env.NODE_ENV='development'
                                "development": [
                                  "last 1 chrome version",
                                  "last 1 firefox version",
                                  "last 1 safari version"
                                ],
                                //生产环境
                                "production": [
                                  ">0.2%",
                                  "not dead",
                                  "not op_mini all"
                                ]
                              }
                            * */
                            // {
                            //     loader: 'postcss-loader',
                            //     options: {
                            //         ident:'postcss',
                            //         plugins: () => [
                            //             //postcss的插件
                            //             require('postcss-preset-env')()
                            //         ]
                            //     }
                            // }
                        ]
                    },
                    {
                        test: /\.less$/,
                        use:[
                            'style-loader',
                            'css-loader',
                            //需要先下载less，在下载less-loader
                            'less-loader',

                        ]
                    },
                    {
                        //处理图片资源，下载两个包url-loader和file-loader
                        test: /\.(jpg|png|gif)$/,
                        loader: 'url-loader',
                        options: {
                            //图片大小小于8kb,就会被base64处理
                            //优点：减少请求数量（减轻服务器压力） 缺点：图片体积会更大
                            limit:8*1024,
                            //问题 url-loader默认使用es6模块化解析，而html-loader引入图片是common.js，解析会出现问题[object Module]
                            //解决
                            esModule:false,
                            //给图片进行重命名
                            //[hash:10]取图片的hash的前10位
                            //[ext]取文件原来的扩展名
                            name:'[hash:10].[ext]',
                            outputPath: "assaet/images",//输出路径
                        },
                        type: 'javascript/auto',

                    },
                    {
                        test: /\.html$/,
                        //处理html文件的img的图片(负责引入img，从而能被url-loader进行处理)
                        loader: 'html-loader',
                    },
                    //打包其他资源（除了html、js、css资源以外的资源）webpack5版本不需要配置都可以打包其他资源如iconfont
                    // {
                    //     //排除css/js/html资源
                    //     exclude: /\.(html|css|js|less|jpg|png|gif)$/,
                    //     loader: 'file-loader',
                    //     options: {
                    //         outputPath: "iconfont",
                    //     }
                    // },
                    /*
                    *
                    * js兼容性处理：babel-loader @babel/core @babel/preset-env
                    *   1、基本js兼容性处理-->@babel/preset-env 只能解决js基础语法，如promise不能转换
                    *   2、全部js兼容性处理-->@babel/polyfill  入口文件 import '@babel/polyfill'
                    *      全部加载的话体积太大。
                    *   3、需要做到兼容性处理：按需加载-->core-js 使用第三种就取消第二种引入
                    *   此thread-loader 开启多线程打包（建议不用）
                    * */
                    {
                        test:/\.js$/,
                        exclude: /node_modules/,
                        loader: 'babel-loader',
                        options: {
                            //预设：指示babel做出怎样的兼容处理
                            presets:[
                                [
                                    '@babel/preset-env',
                                    {
                                        useBuiltIns:'usage',
                                        //指定core-js版本
                                        corejs:{
                                            version:3
                                        },
                                        //指定兼容性做到哪个版本浏览器
                                        targets:{

                                        }
                                    }
                                ]

                            ],
                            //开启bable缓存，第二次构建时会读取缓存
                            cacheDirectory:true
                        }
                    },
                ]
            },

        ]
    },
    //插件，可以用于执行范围更广的任务，如：打包优化和压缩，一直到重新定义环境中的变量等。也需要下载，在使用
    plugins:[
        //详细的plugins的配置
        //html-webpack-plugin,默认创建一个空的html，自动引入打包输出的所有资源（js/css）
        new HtmlWebpackPlugin({
            //复制'./src/index.html'文件，并自动引入打包输出的所有资源(js/css)
            template: './src/index.html',
            //开启压缩html代码
            minify: {
                //移除空格
                collapseWhitespace:true,
                //移除注释
                removeComments:true,
            }
        }),
        new MiniCssExtractPlugin({
            //对输出的css文件重命名
            filename:'css/built.[contenthash:10].css'
        }),
        //压缩css
        new OptimizeCssAssetsWebpackPlugin(),
        // PWA：渐进式网络开发应用程序(离线可访问)
        // new workboxWebpackPlugin.GenerateSW({
        //     /*
        //     * 1、帮助serviceworker快速启动
        //     * 2、删除旧的serviceworker
        //     * */
        //     clientsClaim:true,
        //     skipWaiting:true
        // })
    ],
    //先安装webpack-dev-server 运行npx webpack-dev-server
    devServer: {
        //contentBase:path.resolve(__dirname,'build'),
        //webpack5使用此
        static:path.resolve(__dirname,'build'),
        //启动gzip压缩
        compress:true,
        port:4000,//端口
        open:true,//自动打开浏览器
        /*
            HMR hot module replacement 热模块替换/模块热替换
            作用：一个模块变化，只会打包变化模块
            样式文件：可以使用HMR功能，因为style-loader内部实现了
            js文件：默认不能使用HMR功能--->需要修改js代码，添加支持HMR功能的代码，只能处理非入口js文件的其他文件
            html：默认不能使用HMR功能，同时会影响html不能热更新了(不用做HMR功能)
                解决：修改entry入口，将html文件引入
        */
        hot:true,
        //服务器代理-->解决开发环境的跨域问题
        proxy:{
            '/api':{
                //将devServe的服务器接收到/api/xxx的请求，就会把请求转发到另一个服务器(这里指的就是后端服务器)
                target:'http://localhost:3000',
                //发送请求时，请求路径重写：将/api/xxx-->/xxx(去掉/api)
                pathRewrite:{
                    '^/api':''
                }
            }
        }
    },
    /*
      * source-map: 一种提供源代码到构建后代码映射 技术（如果构建代码出错后，通过映射可以追溯到源代码的错误）
      * source-map:外部
      *   错误代码准确信息 和 源代码的错误位置
      * inline-source-map:内联
      *  只生成一个内联source-map
      *  错误代码准确信息 和 源代码的错误位置
      * hidden-source-map 外部
      *  提示错误原因，到构建后代码位置，不能追溯源代码错误
      * eval-source-map: 内联
      *  每一个文件都生成一个对应的source-map，都在eval
      *    错误代码准确信息 和 源代码的错误位置
      * nosources-source-map:外部
      *   错误代码准确信息，但是没有源代码信息
      * cheap-source-map:外部
      *   错误代码准确信息 和 源代码的错误位置 只能精确到行
      * cheap-module-source-map:外部
      *   错误代码准确信息 和 源代码的错误位置
      * 内联和外部的区别: 1.外部生成了文件，内联没有2.内联构建速度更快
      *
      * 开发环境:速度快，调试更友好
          速度快(eval>inline>cheap>...)
              eval- cheap-souce -map
              eval- source -map
          调试更友好
              souce -map
              cheap-module-souce-map
              cheap-source-map
          --> eval-source-map / eval-cheap-module- souce-map
          生产环境:源代码要不要隐藏?调试要不要更友好
          内联会让代码体积变大，所以在生产环境不用内联
          nosources-source-map全部隐藏
          hidden-source -map只隐藏源代码，会提示构建后代码错误信息
          调试是否友好选择以下
          --> source-map / cheap-module - souce -map
      * */
    devtool:'source-map',
    /*
       code split 代码分割
    * 1、可以将node_modules中的代码单独打包一个chunk最终输出
    * 2、自动分析多入口chunk中，有没有公共的文件。如果有回打包成单独一个chunk
    * */
    optimization: {
        splitChunks: {
            chunks: 'all'
        }
    },
    //拒绝指定的包打包
    externals: {

    },
    //解析模块的规则
    // resolve: {
    //     //配置解析模块路径的别名：优化简写路径 缺点路径没有提示
    //     alias: {
    //         $css: resolve(__dirname,'src/css')
    //     },
    //     //配置省略文件路径的后缀名
    //     //extensions: ['.js','.json']
    //     //告诉webpack解析模块是去找哪个目录
    //     modules: ['node_modules']
    // },
    //mode通过选择 development 或 production 之中的一个，来设置 mode 参数，你可以启用相应模式下的 webpack 内置的优化
   // mode:'development'
};